package com.tool.cn.util;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.util.List;

import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;

/**
 * xml 工具类
 * 
 * @author wangzh 2016年9月20日 下午4:57:14
 */
public final class XmlUtil {

	/**
	 * 获取文件对象
	 * 
	 * @return
	 */
	public static Document read(File file) {
		return read(file, null);
	}
	
	/**
	 * 从指定节点开始,递归遍历所有子节点
	 * @author chenleixing
	 */
	@SuppressWarnings("unchecked")
	public static void getNodes(Element node){
		System.out.println("--------------------");
		
		//当前节点的名称、文本内容和属性
		System.out.println("当前节点名称："+node.getName());//当前节点名称
		System.out.println("当前节点的内容："+node.getTextTrim());//当前节点名称
		List<Attribute> listAttr=node.attributes();//当前节点的所有属性的list
		for(Attribute attr:listAttr){//遍历当前节点的所有属性
			String name=attr.getName();//属性名称
			String value=attr.getValue();//属性的值
			System.out.println("属性名称："+name+"属性值："+value);
		}
		
		//递归遍历当前节点所有的子节点
		List<Element> listElement=node.elements();//所有一级子节点的list
		for(Element e:listElement){//遍历所有一级子节点
			getNodes(e);//递归
		}
	}
	
	/**
	 * 设置编码格式获取文件对象
	 * 
	 * @param file
	 *            文件流
	 * @param charset
	 *            编码格式 UTF-8
	 * @return
	 * @throws DocumentException
	 */
	public static Document read(File file, String charset) {
		if (file == null) {
			return null;
		}
		SAXReader reader = new SAXReader();
		if (StringUtil.isEmpty(charset)) {
			reader.setEncoding(charset);
		}
		Document document = null;
		try {
			document = reader.read(file);
		} catch (DocumentException e) {
			e.printStackTrace();
		}
		return document;
	}

	/**
	 * 获取网络文件对象
	 * 
	 * @param url
	 * @return
	 */
	public static Document read(URL url) {
		return read(url, null);
	}

	/**
	 * 获取网络文件对象，设置编码格式
	 * 
	 */
	public static Document read(URL url, String charset) {
		if (url == null) {
			return null;
		}
		SAXReader reader = new SAXReader();
		if (StringUtil.isEmpty(charset)) {
			reader.setEncoding(charset);
		}
		Document document = null;
		try {
			document = reader.read(url);
		} catch (DocumentException e) {
			e.printStackTrace();
		}
		return document;
	}

	/**
	 * 获取根 节点
	 */
	public static Element getRootElement(Document doc) {
		if (doc == null) {
			return null;
		}
		return doc.getRootElement();
	}

	/**
	 * 获取值 节点eleName下的文本值，若eleName不存在则返回默认值defaultValue
	 */
	public static String getElementValue(Element eleName, String defaultValue) {
		if (eleName == null) {
			return defaultValue == null ? "" : defaultValue;
		} else {
			return eleName.getTextTrim();
		}
	}

	/**
	 * 
	 * @param eleName 子节名称
	 * @param parentElement 当前节点树
	 * @return
	 */
	public static String getElementValue(String eleName, Element parentElement) {
		if (parentElement == null) {
			return null;
		} else {
			Element element = parentElement.element(eleName);
			if (element != null) {
				return element.getTextTrim();
			} else {
				try {
					throw new Exception("找不到节点" + eleName);
				} catch (Exception e) {
					e.printStackTrace();
					return null;
				}
			}
		}
	}
	
	/**
	 * 获取子节点属性值
	 * @param eleName 字节点名
	 * @param parentElement 当前节点树
	 * @param attributes 属性名
	 * @return
	 */
	public static String getElementValue(String eleName, Element parentElement,String attributes) {
		if (parentElement == null) {
			return null;
		} else {
			Element element = parentElement.element(eleName);
			if (element != null) {
				List<Attribute> listAttr=element.attributes();//当前节点的所有属性的list
				String name;
				for(Attribute attr:listAttr){//遍历当前节点的所有属性
					 name=attr.getName();//属性名称
					 if(name.equals(attributes)) {
						 return attr.getValue();
					 }
				}
				return null;
			} else {
				try {
					throw new Exception("找不到节点" + eleName);
				} catch (Exception e) {
					e.printStackTrace();
					return null;
				}
			}
		}
	}

	/**
	 * 获取值 节点eleName下的文本值
	 * 
	 * @param eleName
	 * @return
	 */
	public static String getElementValue(Element eleName) {
		return getElementValue(eleName, null);
	}

	/**
	 * 获取element 节点集合
	 */
	@SuppressWarnings("unchecked")
	public static List<Element> getElement(String eleName, Element parentElement) {
		if (parentElement == null) {
			return null;
		} else {

			List<Element> element = parentElement.elements(eleName);
			if (element != null && element.size() > 0) {
				return element;
			} else {
				try {
					throw new Exception("找不到节点" + eleName);
				} catch (Exception e) {
					e.printStackTrace();
					return null;
				}
			}
		}
	}

	/**
	 * 修改某节点值
	 */
	public static boolean editElement(Element element, String eleName, String value) {
		if (element == null) {
			return false;
		}
		if (StringUtil.isEmpty(value) || StringUtil.isEmpty(eleName)) {
			return false;
		}

		element.element(eleName).setText(value);
		return true;
	}

	/**
	 * 将文档树转换成字符串
	 * 
	 * @param doc
	 * @param isformat 是否格式化
	 * @return
	 */
	public static String xmltoString(Document doc,boolean isFormat) {
		return xmltoString(doc, null,isFormat);
	}

	/**
	 * 将文档树转成字符串，设置编码格式
	 * 	@param doc
	 * @charset 编码格式
	 * @param isformat 是否格式化
	 */
	public static String xmltoString(Document doc, String charset,boolean isFormat) {
		if (doc == null) {
			return "";
		}
		
		if(!isFormat) {
			return doc.asXML();
		}
		
		OutputFormat format = OutputFormat.createPrettyPrint();
		if (StringUtil.isNotEmpty(charset)) {
			format.setEncoding(charset);
		}
//		默认格式化
//		// 设置换行
//		format.setNewlines(true);
//		// 生成缩进
//		format.setIndent(true);
		
		StringWriter strWriter = new StringWriter();
		XMLWriter xmlWriter = new XMLWriter(strWriter, format);
		try {
			xmlWriter.write(doc);
			xmlWriter.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return strWriter.toString();
	}

	/**
	 * 本地存储文件对象
	 */
	public static void xmltoFile(Document doc, File file, String charset) throws Exception {
		if (doc == null) {
			throw new NullPointerException("doc cant not null");
		}
		if (StringUtil.isEmpty(charset)) {
			throw new NullPointerException("charset cant not null");
		}
		OutputFormat format = OutputFormat.createPrettyPrint();
		format.setEncoding(charset);
		FileOutputStream os = new FileOutputStream(file);
		OutputStreamWriter osw = new OutputStreamWriter(os, charset);
		XMLWriter xmlWriter = new XMLWriter(osw, format);
		try {
			xmlWriter.write(doc);
			xmlWriter.close();
			if (osw != null) {
				osw.close();
			}

		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * xml流转存文件
	 */
	public static void xmltoFile(Document doc, String filePath, String charset) throws Exception {
		xmltoFile(doc, new File(filePath), charset);
	}

	/**
	 * document流转存文件
	 */
	public static void writDocumentToFile(Document doc, String filePath, String charset) throws Exception {
		xmltoFile(doc, new File(filePath), charset);
	}

	/**
	 * String 转 xml文件
	 */
	public static Document stringToXml(String text) {
		try {
			return DocumentHelper.parseText(text);
		} catch (DocumentException e) {
			e.printStackTrace();
		}
		return null;
	}

	public static Document createDocument() {
		return DocumentHelper.createDocument();
	}

	/**
	 * 生成xml简单实例
	 */
	public static void createXml() {
		try {
			// 创建文档及设置根元素节点的方式
			Element root = DocumentHelper.createElement("Person");
			Document document = DocumentHelper.createDocument(root);
			// 给根节点添加属性
			root.addAttribute("学校", "南大").addAttribute("位置", "江西");

			// 给根节点添加孩子节点
			Element element1 = root.addElement("学生");
			element1.addElement("姓名").addAttribute("婚姻", "单身").addText("小章");
			element1.addElement("年龄").addText("21");

			Element element2 = root.addElement("学生");
			element2.addElement("姓名").addAttribute("婚姻", "单身").addText("小红").addElement("爱好").addText("唱歌");
			element2.addElement("年龄").addText("22");

			// 把生成的xml文档存放在硬盘上 true代表是否换行
			OutputFormat format = new OutputFormat("    ", true);
			format.setEncoding("UTF-8");// 设置编码格式
			// 设置换行
			format.setNewlines(true);
			// 生成缩进
			format.setIndent(true);
			// 使用4个空格进行缩进, 可以兼容文本编辑器
//			format.setIndent("    ");
			
			XMLWriter xmlWriter = new XMLWriter(new FileOutputStream("Person.xml"), format);

			xmlWriter.write(document);
			xmlWriter.close();

		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

}
